perm filename EXPR.SAI[PNT,HE]1 blob sn#325265 filedate 1977-12-29 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00009 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	entry
C00005 00003	!	compute_func,uncompute_func,error
C00006 00004	!	procedures exp,term,factor,GTOKEN,decode_op
C00014 00005	!	walktree, al version 
C00017 00006	! 	record class declarations: scalar,vector,rot,trans,frame,new_tree
C00020 00007	!	arithcode,makecode 
C00028 00008	!	walktree 
C00035 00009	INTERNAL RPTR(TREE)PROCEDURE GTEXPR
C00037 ENDMK
C⊗;
entry;
BEGIN "GTEXPR"
EXTERNAL STRING TOKEN;

	REQUIRE "[][]" DELIMITERS;
	DEFINE	RPTR	= [RECORD_POINTER],
		RCLASS	= [RECORD_CLASS],
		CRLF	= [('15&'12)],
		$AL$	= [FALSE],
		$POINTY$	= [TRUE],
		SPACE	= [" "],
		NUMERIC_TYPE	= [(2)],
		!	= [COMMENT],
		α	= [BEGIN],
		β	= [END];

!	DEFINE	ID_TYPE	= [(1)];
				define
preload_array(name, defs, type, first, len)=[
	preload_with defs null; type array name[first:first+len] ];

				define

indices(name, postfix)=[
    redefine xxcount=0;
    redefine xx(xxarg)=[
	redefine xxtemp= [ define xxarg]&[postfix=xxcount];
	xxtemp;
	redefine xxcount=xxcount+1;];
    name ];

	define op_list=[
XX(times)
XX(dot)
XX(rel)
XX(backarrow)
XX(divide)
XX(plus)
XX(minus)
XX(WRT)
XX(POS)
XX(UNIT)
XX(AXIS)
XX(ORIENT)
XX(CONSTRUCT)
XX(FRAME)
XX(VECTOR)
XX(TRANS)
XX(MAGNITUDE)
XX(IMPLICIT)
XX(ROT)
];

indices(op_list,_X);


DEFINE #SC=1,#VT=2,#RT=3,#TR=4,#FR=5,#DTYPE=6;

PRELOAD_WITH "NULL","SCALAR","VECTOR","ROT","TRANS","FRAME";
STRING ARRAY $DTYPE[0:5];


DEFINE 		ID_TYPE = 1,
		INT_TYPE = 2,
		REAL_TYPE =  3,
		OPERATOR_TYPE = 4,
		RES_TYPE = 5,
		UNDECLARED_TYPE = 0;
!	compute_func,uncompute_func,error;


EXTERNAL PROCEDURE ERROR(STRING S1,S2(NULL));


INTEGER PROCEDURE COMPUTE_FUNC(INTEGER I1,I2,I3,I4,I5);
	RETURN(((((I1*#DTYPE +I2)*#DTYPE + I3)*#DTYPE) + I4)*#DTYPE +I5);

INTEGER PROCEDURE UNCOMPUTE_FUNC(INTEGER I1,I2);
	α INTEGER I;
		CASE I2 OF
			α	[1]	I←I1 DIV #DTYPE↑4;
				[2]	I←(I1 DIV #DTYPE↑3)MOD #DTYPE;
				[3]	I←(I1 DIV #DTYPE↑2) MOD #DTYPE;
				[4]	I←(I1 DIV #DTYPE) MOD #DTYPE;
				[5]	I←I1 MOD #DTYPE;
				ELSE ERROR("WRONG FIELD IN UNCOMPPUTE_FUNC PARSER ERROR")
			β;
	RETURN(I);
	β;

!	procedures exp,term,factor,GTOKEN,decode_op;

!	E:	{+|-} T {+|- T }

	T:	F {*|/ F}

	F:	( E ), 
		f(  ,  ,  ...)
		<constant>,
		<id>,	;

EXTERNAL PROCEDURE GTOKEN(BOOLEAN AGAIN(TRUE));
EXTERNAL INTEGER #TOKEN;
EXTERNAL BOOLEAN STOKEN;


RCLASS EXP_REC (STRING $OP; RPTR(EXP_REC) SON,YBRO);

FORWARD RECURSIVE RPTR(EXP_REC) PROCEDURE EXP;
FORWARD RECURSIVE RPTR(EXP_REC) PROCEDURE TERM;
FORWARD RECURSIVE RPTR(EXP_REC) PROCEDURE FACTOR;

RPTR(EXP_REC) PROCEDURE NEW_EXP_REC(RPTR(EXP_REC)T1;STRING $OP;RPTR(EXP_REC)T2);
α RPTR(EXP_REC)R1; R1←NEW_RECORD(EXP_REC);
	EXP_REC:$OP[R1]←$OP;
	EXP_REC:SON[R1]←T1;
	EXP_REC:YBRO[R1]←T2;
  RETURN(R1);
β;

RPTR(EXP_REC) PROCEDURE TERM_EXP_REC(STRING $TERM);
α RPTR(EXP_REC)R1; R1←NEW_RECORD(EXP_REC);
	EXP_REC:$OP[R1]←$TERM;
	RETURN(R1);
β;

RECURSIVE RPTR (EXP_REC) PROCEDURE EXP;
α	RPTR (EXP_REC) T1,T2; STRING $OP;
	IF TOKEN="+" OR TOKEN ="-"
	THEN α  $OP←TOKEN; GTOKEN;
		IF (T1←TERM)=NULL_RECORD
		THEN ERROR("Null term after a " &$OP);
		IF $OP="-"
		     THEN T1←NEW_EXP_REC(T1,$OP,NULL_RECORD);
	     β
	ELSE T1←TERM;

	WHILE TOKEN= "+" OR TOKEN = "-" DO 
	    α $OP ← TOKEN; GTOKEN;
		IF (T2←TERM)=NULL_RECORD 
		THEN error("Null term after an "&$OP);
		T1←NEW_EXP_REC(T1, $OP, T2);
	    β;
	RETURN(T1);
β;

RECURSIVE RPTR (EXP_REC) PROCEDURE TERM;
α	RPTR (EXP_REC) T1,T2; STRING $OP;
	T1←FACTOR;
	WHILE TOKEN = "*" OR TOKEN="/" OR TOKEN = "." OR TOKEN="→" OR
		EQU(TOKEN,"WRT") OR EQU(TOKEN,"REL") DO
	    α	$OP←TOKEN;
		IF T1=NULL_RECORD
		THEN ERROR("null factor before a "&$OP);
		GTOKEN;
		IF (T2←FACTOR)=NULL_RECORD
		THEN ERROR("Null factor after a "&$OP);
		IF T1=NULL_RECORD THEN T1←NEW_EXP_REC(T2,$OP,NULL_RECORD)
		ELSE T1←NEW_EXP_REC(T1,$OP,T2);
	    β;
	RETURN(T1);
β;

RECURSIVE RPTR (EXP_REC) PROCEDURE FACTOR;
α	RPTR (EXP_REC) T1,T2,T3; STRING $OP;
IFC $AL$ THENC ! AL PARSER ;
	IF TOKEN = "("
	THEN α GTOKEN;
		IF (T1←EXP)=NULL_RECORD THEN ERROR("null expression found after (");
		IF TOKEN≠")" THEN error("require close paren here")
		ELSE GTOKEN;
	     β
	ELSE ENDC
	IF TOKEN = "|"
	THEN α GTOKEN;
		IF (T1←EXP)=NULL_RECORD THEN ERROR("null expression found after |");
		IF TOKEN≠"|" THEN error("require | paren here")
			ELSE GTOKEN;
		T1←NEW_EXP_REC(T1,"MAGNITUDE",NULL_RECORD);
	     β
	ELSE IF EQU(TOKEN,"POS") OR EQU(TOKEN,"UNIT") OR EQU(TOKEN,"AXIS")
		OR EQU(TOKEN,"ORIENT") OR EQU(TOKEN,"CONSTRUCT") OR 
		EQU(TOKEN,"FRAME") OR EQU(TOKEN,"VECTOR") OR EQU(TOKEN,"TRANS")
		OR EQU(TOKEN,"ROT") IFC $POINTY$ THENC OR EQU(TOKEN,"(") ENDC THEN
	     α
		IFC $POINTY$ THENC
			IF TOKEN="("
			THEN α  $OP←"IMPLICIT"; GTOKEN; β
			ELSE α 	$OP←TOKEN; GTOKEN;
				IF TOKEN≠"(" THEN error("require close paren after "&$OP)
				ELSE GTOKEN; β;
		ELSEC	$OP←TOKEN; GTOKEN;
			IF TOKEN≠"(" THEN error("require close paren after "&$OP)
			ELSE GTOKEN;
		ENDC
		IF (T1←EXP)=NULL_RECORD THEN ERROR("unexpected token after "&$OP&" (");
		T2←new_exp_rec(t1,NULL,null_record);
		T1←NEW_EXP_REC(T2,$OP,NULL_RECORD);
		WHILE TOKEN="," DO
			α GTOKEN;
			IF (T3←EXP)= NULL_RECORD THEN ERROR("unexpected token after ,");
			T3←NEW_EXP_REC(T3,NULL,NULL_RECORD);
			EXP_REC:YBRO[T2]←T3; T2←T3; 
			β;
		IF TOKEN≠")" THEN ERROR("require , or ) here, will insert )")
			ELSE GTOKEN(FALSE);
		IFC $POINTY$ THENC
			IF EQU($OP,"IMPLICIT") AND EXP_REC:YBRO[EXP_REC:SON[T1]] = NULL_RECORD
			THEN T1←EXP_REC:SON[EXP_REC:SON[T1]]; ENDC
	     β
	ELSE CASE #TOKEN OF
		α
		[id_type] α T1←TERM_EXP_REC("$"&TOKEN); GTOKEN(FALSE); β;
		[int_type] α T1←TERM_EXP_REC("#"&TOKEN); GTOKEN(FALSE); β;
		[real_type] α T1←TERM_EXP_REC("%"&TOKEN); GTOKEN(FALSE); β;
		[operator_type]	error("unexpected operator "&token);
		[undeclared_type]	error("undeclared token "&token);
		else error("unexpected token "&token)
		β;

RETURN(t1);
β;

integer procedure decode_op(STRING OP);
α INTEGER Q;
	CASE OP OF
		α	["+"]	Q←PLUS_X;
			["-"]	Q←MINUS_X;
			["*"]	Q←TIMES_X;
			["/"]	Q←DIVIDE_X;
			["→"]	Q←BACKARROW_X;
			["."]	Q←DOT_X;
		
		ELSE IF EQU(OP,"REL") THEN Q←REL_X
		ELSE IF EQU(OP,"WRT") THEN Q←WRT_X
		ELSE IF EQU(OP,"MAGNITUDE") THEN Q←MAGNITUDE_X
		ELSE IF EQU(OP,"POS") THEN Q←POS_X
		ELSE IF EQU(OP,"UNIT") THEN Q←UNIT_X
		ELSE IF EQU(OP,"AXIS") THEN Q←AXIS_X
		ELSE IF EQU(OP,"ORIENT") THEN Q←ORIENT_X
		ELSE IF EQU(OP,"CONSTRUCT") THEN Q←CONSTRUCT_X
		ELSE IF EQU(OP,"FRAME") THEN Q←FRAME_X
		ELSE IF EQU(OP,"VECTOR") THEN Q←VECTOR_X
		ELSE IF EQU(OP,"TRANS") THEN Q←TRANS_X
		ELSE IF EQU(OP,"IMPLICIT") THEN Q←IMPLICIT_X
		ELSE IF EQU(OP,"ROT") THEN Q←ROT_X
		ELSE Q←0

		β;
RETURN(Q);
β;
!	walktree, al version ;

IFC $AL$ THENC
RECURSIVE STRING PROCEDURE WALKTREE(RPTR(EXP_REC)T1);
α STRING S1;
	IF T1=NULL_RECORD
	THEN RETURN(NULL)
	ELSE IF EXP_REC:SON[T1]=NULL_RECORD
	THEN RETURN(EXP_REC:$OP[T1])
	ELSE IF EQU(EXP_REC:$OP[T1],NULL)
	THEN RETURN(NULL)
	ELSE IF EQU(EXP_REC:$OP[T1],"*") OR
		EQU(EXP_REC:$OP[T1],"/") OR
		EQU(EXP_REC:$OP[T1],"+") OR
		EQU(EXP_REC:$OP[T1],"-") OR
		EQU(EXP_REC:$OP[T1],".") OR
		EQU(EXP_REC:$OP[T1],"→") OR
		EQU(EXP_REC:$OP[T1],"WRT") OR
		EQU(EXP_REC:$OP[T1],"MAGNITUDE") OR
		EQU(EXP_REC:$OP[T1],"REL")
	THEN RETURN(CRLF & "( "& EXP_REC:$OP[T1] & CRLF
			& "  " & WALKTREE(EXP_REC:SON[T1]) &
			"  "&(IF EXP_REC:YBRO[T1]≠NULL_RECORD THEN
			CRLF & "  " &WALKTREE(EXP_REC:YBRO[T1]) ELSE NULL) & " )")

	ELSE IF EQU(EXP_REC:$OP[T1],"POS") OR
		EQU(EXP_REC:$OP[T1],"UNIT") OR
		EQU(EXP_REC:$OP[T1],"AXIS") OR
		EQU(EXP_REC:$OP[T1],"ORIENT") OR
		EQU(EXP_REC:$OP[T1],"CONSTRUCT") OR 
		EQU(EXP_REC:$OP[T1],"FRAME") OR
		EQU(EXP_REC:$OP[T1],"VECTOR") OR
		EQU(EXP_REC:$OP[T1],"TRANS") OR
		EQU(EXP_REC:$OP[T1],"IMPLICIT") OR
		EQU(EXP_REC:$OP[T1],"ROT")
	THEN	α RPTR(EXP_REC)T2; S1←WALKTREE(EXP_REC:SON[T2←EXP_REC:SON[T1]]);
		WHILE (T2← EXP_REC:YBRO[T2])≠NULL_RECORD
			DO S1←S1&"  "&WALKTREE(EXP_REC:SON[T2]);
		RETURN(CRLF & "( "&EXP_REC:$OP[T1]&" " &S1&" )");
		β
	ELSE	ERROR("EXPRESSION PARSER ERROR, FOUND "&EXP_REC:$OP[T1]);
β;

ELSEC

! 	record class declarations: scalar,vector,rot,trans,frame,new_tree;
EXTERNAL RCLASS SCALAR (REAL VALUE);
		! value=value of the scalar;

EXTERNAL RCLASS VECTOR (REAL XC,YC,ZC);
		! xc,yc,zc=value of the component of the vector along x,y,z axis;

EXTERNAL RCLASS FRAME (STRING PNAME; RPTR (FRAME) DAD,SON,EBRO,YBRO; INTEGER HOWLINKED;
              REAL ARRAY XF);
		! pname=pname of the frame;
		! dad,son,ebro,ybro=pointers to dad,son,elder and younger brother
		  in frame tree;
		! howlinked=kind of affixment(rigid,nonrigid,independent);
		! xf=array of values
		  xf[1:3,1:3]=rotation matrix,
		  xf[1:3,4]=translation vector,
		  xf[4,1:3]=0,
		  xf[4,4]=1,
		  xf[5,1:3]=rotation angles,
		  xf[5,4]>0 if angles are valid;

EXTERNAL RCLASS ROT (REAL ARRAY XF);
		! xf=array of values (as for frame class);

EXTERNAL RCLASS TRANS(REAL ARRAY XF);
		! xf=array of values (as for frame class);
		! records not entered in $YMTAB, used for computations;
INTERNAL RCLASS TREE(RPTR(SCALAR,VECTOR,TRANS,ROT,FRAME)DATA; INTEGER DTYPE);

INTERNAL RPTR(TREE)PROCEDURE NWTREE(RPTR(SCALAR, VECTOR,ROT,TRANS,FRAME) R; INTEGER T);
	α RPTR(TREE) K; K←NEW_RECORD(TREE);
	TREE:DATA[K]←R; TREE:DTYPE[K]←T; RETURN(K); β;

!	arithcode,makecode ;

REQUIRE "EXPINT.MLG[1,MLG]" SOURCE_FILE;
REQUIRE "⊂⊃⊂⊃" REPLACE_DELIMITERS;

DEFINE OPCODE = ⊂
XX("*",	TIMES_X,	#SC,	#SC,	#SC,	⊂OPSCAL(#1,#2,#3,"*")⊃)
XX("*",	TIMES_X,	#SC,	#VT,	#VT,	⊂OPSCVT(#1,#2,#3,"*")⊃)
XX("*",	TIMES_X,	#VT,	#SC,	#VT,	⊂OPSCVT(#2,#1,#3,"*")⊃)
XX("*",	TIMES_X,	#RT,	#RT,	#RT,	⊂OPRTRT(#1,#2,#3)⊃)
XX("*",	TIMES_X,	#RT,	#VT,	#VT,	⊂OPRTVT(#1,#2,#3)⊃)
XX("*",	TIMES_X,	#TR,	#VT,	#VT,	⊂OPTRVT(#1,#2,#3)⊃)
XX("*",	TIMES_X,	#TR,	#TR,	#TR,	⊂OPTRTR(#1,#2,#3)⊃)
XX("*",	TIMES_X,	#TR,	#FR,	#FR,	⊂OPTRFR(#1,#2,#3)⊃)
XX("*",	TIMES_X,	#FR,	#FR,	#FR,	⊂OPFR(#1,#2,#3)⊃)

XX(".",	DOT_X,		#VT,	#VT,	#SC,	⊂OPDOT(#1,#2,#3)⊃)

XX("REL",	REL_X,	#VT,	#FR,	#VT,	⊂OPVTFR(#2,#1,#3)⊃)

XX("→",	BACKARROW_X,	#FR,	#FR,	#TR,	⊂OPFRFR(#1,#2,#3)⊃)

XX("/",	DIVIDE_X,	#SC,	#SC,	#SC,	⊂OPSCAL(#1,#2,#3,"/")⊃)
XX("/",	DIVIDE_X,	#VT,	#SC,	#VT,	⊂OPSCVT(#2,#1,#3,"/")⊃)

XX("+",	PLUS_X,		#SC,	0,	#SC,	⊂OPSCAL(#1,0,#3,"+")⊃)
XX("+",	PLUS_X,		#VT,	0,	#VT,	⊂OPVET(#1,NEW_RECORD(VECTOR),#3,"+")⊃)
XX("+",	PLUS_X,		#SC,	#SC,	#SC,	⊂OPSCAL(#1,#2,#3,"+")⊃)
XX("+",	PLUS_X,		#VT,	#VT,	#VT,	⊂OPVET(#1,#2,#3,"+")⊃)
XX("+",	PLUS_X,		#FR,	#VT,	#FR,	⊂OPFRVT(#2,#1,#3,"+")⊃)
XX("+",	PLUS_X,		#VT,	#FR,	#FR,	⊂OPFRVT(#1,#2,#3,"+")⊃)

XX("-",	MINUS_X,		#SC,	0,	#SC,	⊂OPSCAL(0,#1,#3,"-")⊃)
XX("-",	MINUS_X,		#VT,	0,	#VT,	⊂OPVET(NEW_RECORD(VECTOR),#1,#3,"-")⊃)
XX("-",	MINUS_X,		#SC,	#SC,	#SC,	⊂OPSCAL(#1,#2,#3,"-")⊃)
XX("-",	MINUS_X,		#VT,	#VT,	#VT,	⊂OPVET(#1,#2,#3,"-")⊃)
XX("-",	MINUS_X,	#FR,	#VT,	#FR,	⊂OPFRVT(#2,#1,#3,"-")⊃)

⊃;

DEFINE MKCODE = ⊂
XX("POS",	POS_X,		FPOS,	#VT,	1,	#FR,	0,	0)
XX("POS",	POS_X,		TPOS,	#VT,	1,	#TR,	0,	0)
XX("UNIT",	UNIT_X,		NORMVT,	#VT,	1,	#VT,	0,	0)
! XX("AXIS",	AXIS_X,		FAXIS,	#VT,	1,	#RT,	0,	0) ;
! XX("ORIENT",	ORIENT_X,	FORIENT,#RT,	1,	#TR,	0,	0) ;
! XX("REL",	REL_X,		RELVT,	#VT,	2,	#VT,	#FR,	0) ;
! XX("REL",	REL_X,		RELFR,	#FR,	2,	#FR,	#TR,	0) ;
! XX("WRT",	WRT_X,		WRTVT,	#VT,	2,	#VT,	#FR,	0) ;
XX("ORIENT",	ORIENT_X,	FORIEN,	#RT,	1,	#FR,	0,	0)
XX("TRANS",	TRANS_X,	TMAKE,	#TR,	2,	#RT,	#VT,	0)
XX("ROT",	ROT_X,		RMAKE,	#RT,	2,	#VT,	#SC,	0)
XX("FRAME",	FRAME_X,	FMAKE,	#FR,	2,	#RT,	#VT,	0) 
XX("VECTOR",	VECTOR_X,	VMAKE,	#VT,	3,	#SC,	#SC,	#SC)
XX("CONSTRUCT",	CONSTRUCT_X,	CONSV,	#FR,	3,	#VT,	#VT,	#VT)
XX("CONSTRUCT",	CONSTRUCT_X,	CONSF,	#FR,	3,	#FR,	#FR,	#FR)
XX("MAGNITUDE",	MAGNITUDE_X,	SMOD,	#SC,	1,	#SC,	0,	0)
XX("MAGNITUDE",	MAGNITUDE_X,	VMOD,	#SC,	1,	#VT,	0,	0)
! XX("MAGNITUDE",	MAGNITUDE_X,	RMOD,	#SC,	1,	#RT,	0,	0) ;
XX("IMPLICIT",	IMPLICIT_X,		VMAKE,	#VT,	3,	#SC,	#SC,	#SC)
XX("IMPLICIT",	IMPLICIT_X,	RMAKE,	#RT,	2,	#VT,	#SC,	0)
XX("IMPLICIT",	IMPLICIT_X,	TMAKE,	#TR,	2,	#RT,	#VT,	0)
⊃;
RECURSIVE RPTR(TREE) PROCEDURE MAKE_CODE(STRING $OP;RPTR(TREE)R1,R2,R3,R4);
α	RPTR(TREE)X1; INTEGER PP;
REDEFINE XX(OP,OP_TYPE,OP_FUNC,OP_DTYPE,#n,#1,#2,#3) = ⊂
	redefine xx_val = (((op_type*#dtype + #1)* #dtype + #2)*#dtype + #3)*#DTYPE ;
	redefine xx_temp = ⊂ IF PP=xx_val THEN
			   CASEC #n OFC
				⊂X1←NWTREE(OP_FUNC,OP_DTYPE)⊃,
				⊂X1←NWTREE(OP_FUNC(TREE:DATA[R1]),OP_DTYPE)⊃,
				⊂X1←NWTREE(OP_FUNC(TREE:DATA[R1],TREE:DATA[R2]),OP_DTYPE)⊃,
				⊂X1←NWTREE(OP_FUNC(TREE:DATA[R1],TREE:DATA[R2],TREE:DATA[R3]),OP_DTYPE)⊃,
			   ⊂REQUIRE " HAH" MESSAGE;⊃ ENDC
			   ELSE ⊃;
	xx_temp ⊃;

	PP←COMPUTE_FUNC(DECODE_OP($OP),
		(IF R1≠NULL_RECORD THEN TREE:DTYPE[R1] ELSE 0),
		(IF R2≠NULL_RECORD THEN TREE:DTYPE[R2] ELSE 0),
		(IF R3≠NULL_RECORD THEN TREE:DTYPE[R3] ELSE 0),
		(IF R4≠NULL_RECORD THEN TREE:DTYPE[R4] ELSE 0));
	MKCODE
	ERROR($OP&" cannot take argument(s) type(s) "&
		(IF R1≠NULL_RECORD THEN $DTYPE[TREE:DTYPE[R1]]&", " ELSE NULL)&
		(IF R2≠NULL_RECORD THEN $DTYPE[TREE:DTYPE[R2]]&", " ELSE NULL)&
		(IF R3≠NULL_RECORD THEN $DTYPE[TREE:DTYPE[R3]]&", " ELSE NULL)&
		(IF R4≠NULL_RECORD THEN $DTYPE[TREE:DTYPE[R4]]&", " ELSE NULL));

	return(X1);

β;

RECURSIVE RPTR(TREE)PROCEDURE ARITH_CODE(RPTR(TREE)R1,R2; STRING $OP);
α	INTEGER SUB_TYPE; RPTR(TREE) R3; INTEGER PP;
		SUB_TYPE←0; R3←NEW_RECORD(TREE);

REDEFINE XX(OP,OP_TYPE,TYPE1,TYPE2,TYPE3,FUNC) =
	⊂ redefine xx_val =  (op_type* #dtype + type1)* #dtype +type2 ;
		redefine #1 = ⊂
			redefine xx_1 =  IFC TYPE1= #SC THENC ⊂SCALAR:VALUE[TREE:DATA[R1]]⊃
				ELSEC ⊂TREE:DATA[R1]⊃ ENDC; 
			xx_1⊃;
		redefine #2 = ⊂
			redefine xx_2 = IFC TYPE2= #SC THENC ⊂SCALAR:VALUE[TREE:DATA[R2]]⊃
				ELSEC ⊂TREE:DATA[R2]⊃ ENDC;
			xx_2⊃;
		redefine #3 = ⊂TREE:DATA[R3]⊃;
	  redefine xx_temp = ⊂
		[ xx_val ] BEGIN 
		IFC (#SC≤TYPE3≤#FR) THENC
			TREE:DATA[R3]←MK_REC(TYPE3);
		ELSEC	REQUIRE " HAH " MESSAGE; ENDC
			   func ; TREE:DTYPE[R3]←TYPE3; END; ⊃ ;
	  xx_temp ⊃;

	CASE (PP←COMPUTE_FUNC(0,0,DECODE_OP($OP),TREE:DTYPE[R1],
		(IF R2=NULL_RECORD THEN 0 ELSE TREE:DTYPE[R2]))) OF
	α
	OPCODE
	ELSE  ERROR($OP&" cannot take argument(s) type(s) "&
		(IF R1≠NULL_RECORD THEN $DTYPE[TREE:DTYPE[R1]] ELSE "***")&
		(IF R2≠NULL_RECORD THEN ", "&$DTYPE[TREE:DTYPE[R2]] ELSE NULL))
	β;

	return(R3);
β;

!	walktree ;
RECURSIVE RPTR(TREE) PROCEDURE WALKTREE(RPTR(EXP_REC)T1);
α RPTR(TREE)R1,R2,R3;
	IF T1=NULL_RECORD
	THEN RETURN(NULL_RECORD)
	ELSE IF EXP_REC:SON[T1]=NULL_RECORD
	THEN α	STRING S; S←EXP_REC:$OP[T1];
		CASE LOP(S) OF 
		α
		["$"]	RETURN(DCDSYM(S));
		["#"]
		["%"]	α RPTR(SCALAR)Q1; INTEGER I;
			Q1←NEW_RECORD(SCALAR);
			SCALAR:VALUE[Q1]←REALSCAN(S,I);
			RETURN(NWTREE(Q1,#SC));β;

		ELSE	ERROR("PARSER ERROR, TELL SOMEBODY")
	     β  β
	ELSE IF EQU(EXP_REC:$OP[T1],NULL)
	THEN RETURN(NULL_RECORD)
	ELSE IF EQU(EXP_REC:$OP[T1],"*") OR
		EQU(EXP_REC:$OP[T1],"/") OR
		EQU(EXP_REC:$OP[T1],"+") OR
		EQU(EXP_REC:$OP[T1],"-") OR
		EQU(EXP_REC:$OP[T1],".") OR
		EQU(EXP_REC:$OP[T1],"→") OR
		EQU(EXP_REC:$OP[T1],"WRT") OR
		EQU(EXP_REC:$OP[T1],"REL")
	THEN 	α R1←WALKTREE(EXP_REC:SON[T1]);
		R2←WALKTREE(EXP_REC:YBRO[T1]);
		RETURN(ARITH_CODE(R1,R2,EXP_REC:$OP[T1])); β
	ELSE IF EQU(EXP_REC:$OP[T1],"POS") OR
		EQU(EXP_REC:$OP[T1],"UNIT") OR
		EQU(EXP_REC:$OP[T1],"AXIS") OR
		EQU(EXP_REC:$OP[T1],"ORIENT") OR
		EQU(EXP_REC:$OP[T1],"TRANS") OR
		EQU(EXP_REC:$OP[T1],"ROT") OR
		EQU(EXP_REC:$OP[T1],"FRAME") OR
		EQU(EXP_REC:$OP[T1],"VECTOR") OR
		EQU(EXP_REC:$OP[T1],"MAGNITUDE") OR
		EQU(EXP_REC:$OP[T1],"CONSTRUCT") OR 
		EQU(EXP_REC:$OP[T1],"IMPLICIT")
	THEN	α RPTR(EXP_REC)T2;RPTR(TREE)R1,R2,R3,R4;
		R1←WALKTREE(EXP_REC:SON[T2←EXP_REC:SON[T1]]);
		IF (T2← EXP_REC:YBRO[T2])≠NULL_RECORD THEN
			α  R2←WALKTREE(EXP_REC:SON[T2]);
			   IF (T2←EXP_REC:YBRO[T2])≠NULL_RECORD THEN
				α R3←WALKTREE(EXP_REC:SON[T2]);
				IF (T2←EXP_REC:YBRO[T2])≠NULL_RECORD THEN
					R4←WALKTREE(EXP_REC:SON[T2]);
				β;
			β;
		RETURN(MAKE_CODE(EXP_REC:$OP[T1],R1,R2,R3,R4));
		β

	ELSE	ERROR("EXPRESSION PARSER ERROR, FOUND "&EXP_REC:$OP[T1]);
β;

ENDC
INTERNAL RPTR(TREE)PROCEDURE GTEXPR;
α RPTR(EXP_REC) T1;RPTR(TREE)T2;
	GTOKEN;
	T1←EXP;
	T2←WALKTREE(T1);
	STOKEN←TRUE;
	RETURN(T2);
β;

END;